Completed
Push — master ( dd0888...3b0b80 )
by Maxence
07:17
created

Navigate.onEntryGenerated   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 1
1
/*
2
 * FullTextSearch - Full text search framework for Nextcloud
3
 *
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later. See the COPYING file.
6
 *
7
 * @author Maxence Lange <[email protected]>
8
 * @copyright 2018
9
 * @license GNU AGPL version 3 or any later version
10
 *
11
 * This program is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License as
13
 * published by the Free Software Foundation, either version 3 of the
14
 * License, or (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 */
25
26
27
/** global: OCA */
28
/** global: _ */
29
30
var fullTextSearch = OCA.FullTextSearch.api;
31
32
33
var elements = {
34
	searchTimeout: null,
35
	search_input: null,
36
	search_submit: null,
37
	search_result: null,
38
	search_json: null
39
};
40
41
var Navigate = function () {
42
	this.init();
43
};
44
45
Navigate.prototype = {
46
47
	currentTagsResult: {},
48
	selectedTags: {},
49
50
	init: function () {
51
		var self = this;
52
53
		elements.search_input = $('#search_input');
54
		elements.search_submit = $('#search_submit');
55
		elements.search_result = $('#search_result');
56
		elements.search_panels = $('#search_navigation');
57
//		elements.search_json = $('#search_json');
58
		elements.divHeader = $('#search_header');
59
		box_elements.searchError = $('#search_error');
0 ignored issues
show
Bug introduced by
The variable box_elements seems to be never declared. If this is a global, consider adding a /** global: box_elements */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
60
61
		fullTextSearch.setEntryTemplate($('#template_entry'), self);
62
		fullTextSearch.setResultContainer(elements.search_result);
63
64
		elements.search_input.on('input', function () {
65
			self.resetSearch();
66
			if (elements.searchTimeout === null && self.initSearch()) {
67
				elements.searchTimeout = _.delay(function () {
68
					self.initSearch();
69
					elements.searchTimeout = null;
70
				}, 3000);
71
			}
72
		});
73
74
		//
75
		// $(document).keypress(function (e) {
76
		// 	if (e.which === 13) {
77
		// 		self.initSearch(true);
78
		// 	}
79
		// });
80
81
		self.initPanels();
82
	},
83
84
85
	initPanels: function () {
86
		var self = this;
87
88
		$.ajax({
89
			method: 'GET',
90
			url: OC.generateUrl('/apps/fulltextsearch/navigation/panels')
0 ignored issues
show
Bug introduced by
The variable OC seems to be never declared. If this is a global, consider adding a /** global: OC */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
91
		}).done(function (res) {
92
			self.displayPanels(res);
93
		});
94
	},
95
96
97
	displayPanels: function (data) {
98
		var self = this;
99
100
		var ak = Object.keys(data);
101
		for (var i = 0; i < ak.length; i++) {
102
			var providerAppId = ak[i];
103
			var title = data[ak[i]]['title'];
0 ignored issues
show
Coding Style introduced by
['title'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
104
			var nav = data[ak[i]]['navigation'];
0 ignored issues
show
Coding Style introduced by
['navigation'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
105
			var providerId = data[ak[i]]['provider'];
0 ignored issues
show
Coding Style introduced by
['provider'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
106
107
			if (nav.css !== undefined) {
108
				OC.addStyle(providerAppId, nav.css);
0 ignored issues
show
Bug introduced by
The variable OC seems to be never declared. If this is a global, consider adding a /** global: OC */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
109
			}
110
111
			var li = $('<li>', {class: (nav.options !== undefined) ? 'collapsible open' : ''});
112
			var aIcon = $('<a>', {
113
				href: '#',
114
				class: (nav.icon !== undefined) ? nav.icon : 'search_icon'
115
			});
116
			aIcon.text(title);
117
118
			var ul = $('<ul>');
119
			if (nav.options !== undefined) {
120
121
				aIcon.on('click', function () {
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
122
					var li = $(this).closest('li');
123
					if (li.hasClass('open')) {
124
						li.removeClass('open');
125
					} else {
126
						li.addClass('open');
127
					}
128
				});
129
130
				for (var j = 0; j < nav.options.length; j++) {
131
					var sub = nav.options[j];
132
					self.displayPanelCheckbox(ul, sub);
133
					self.displayPanelInput(ul, sub);
134
					self.displayPanelTags(ul, sub);
135
					self.displayPanelSearch(providerAppId, ul, sub);
136
					//
137
					// <p id="tag_filter" class="open">
138
					// 		<input value="" style="display: none;" type="text">
139
					// 		<ul class="tagit ui-widget ui-widget-content ui-corner-all">
140
					// 		<li class="tagit-new">
141
					// 		<input class="ui-widget-content ui-autocomplete-input"
142
					// placeholder="Filter by tag" autocomplete="off" type="text"> <span role="status"
143
					// aria-live="polite" class="ui-helper-hidden-accessible"> 1 result is available,
144
					// use up and down arrow keys to navigate.</span></li> <li class="tagit-choice
145
					// ui-widget-content ui-state-default ui-corner-all"> <span
146
					// class="tagit-label">test</span><a class="close"><span class="text-icon">×</span>
147
					// <span class="ui-icon ui-icon-close"></span></a></li> <li class="tagit-choice
148
					// ui-widget-content ui-state-default ui-corner-all"> <span
149
					// class="tagit-label">perdu</span><a class="close"><span class="text-icon">×</span>
150
					// <span class="ui-icon ui-icon-close"></span></a></li></ul> </p>
151
152
153
				}
154
			}
155
156
			li.append(aIcon);
157
			var aInput = $('<input>', {
158
				class: 'search_checkbox',
159
				type: 'checkbox',
160
				'data-provider': ak[i],
161
				'data-provider-id': providerId
162
			});
163
			aInput.change(function () {
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
164
				self.initSearch();
165
			});
166
167
			li.append(aInput);
168
			li.append(ul);
169
170
			elements.search_panels.append(li);
171
		}
172
173
	},
174
175
176
	displayPanelOptionTitle (sub) {
0 ignored issues
show
Backwards Compatibility introduced by
'concise methods' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
Loading history...
177
		return $('<a>', {
178
			href: '#',
179
			class: 'ulsub',
180
			text: sub.title
181
		});
182
	},
183
184
185
	displayPanelCheckbox: function (ul, sub) {
186
187
		if (sub.type !== 'checkbox') {
188
			return;
189
		}
190
191
		var self = this;
192
		var subA = this.displayPanelOptionTitle(sub);
193
		var subAInput = $('<input>', {
194
			class: 'search_checkbox_sub',
195
			type: 'checkbox',
196
			'data-option': sub.name
197
		});
198
		subAInput.change(function () {
199
			self.initSearch();
200
		});
201
202
		ul.append($('<li>').append(subA).append(subAInput));
203
	},
204
205
206
	displayPanelInput: function (ul, sub) {
207
		if (sub.type !== 'input') {
208
			return;
209
		}
210
211
		var self = this;
212
		var subA = this.displayPanelOptionTitle(sub);
213
		var subAInput = $('<input>', {
214
			class: 'search_input_sub search_input_sub_' + sub.size,
215
			type: 'text',
216
			placeholder: sub.placeholder,
217
			'data-option': sub.name
218
		});
219
		subAInput.on('input', function () {
220
			self.initSearch();
221
		});
222
223
		ul.append($('<li>').append(subA).append(subAInput));
224
	},
225
226
227
	displayPanelTags: function (ul, sub) {
228
		if (sub.type !== 'tags') {
229
			return;
230
		}
231
232
		var self = this;
0 ignored issues
show
Unused Code introduced by
The variable self seems to be never used. Consider removing it.
Loading history...
233
		var subAInput = $('<input>', {
234
			id: sub.name,
235
			class: 'search_tags_sub',
236
			type: 'text',
237
			placeholder: sub.title,
238
			list: sub.name + '_datalist',
239
			'data-option': sub.name
240
		});
241
242
		var subADataList = $('<datalist>', {
243
			id: sub.name + '_datalist'
244
		});
245
246
		sub.list.forEach(function (item) {
247
			subADataList.append($('<option>', {value: item}));
248
		});
249
250
251
		/**
252
		 * <div class="systemTagsInfoView">
253
		 *       <div class="systemTagsInputFieldContainer">
254
		 *           <div id="s2id_autogen15" class="select2-container select2-container-multi
255
		 * systemTagsInputField systemtags-select2-container">
256
		 *               <ul class="select2-choices">
257
		 *                   <li class="select2-search-choice">
258
		 *                       <div>
259
		 *                           <span class="label">dsfsdfds</span>
260
		 *                       </div>
261
		 *                       <a href="#" class="select2-search-choice-close" tabindex="-1"></a>
262
		 *                   </li>
263
		 *               </ul>
264
		 *           </div>
265
		 *           <input class="systemTagsInputField select2-offscreen" name="tags"
266
		 * value="5,4,3,1,2,6" tabindex="-1" type="hidden">
267
		 *       </div>
268
		 * </div>
269
		 */
270
		// subAInput.on('change', function (e) {
271
		// 	var div = $(this);
272
		// 	if (e.which === 13 && div.val() !== '') {
273
		// 		self.selectPanelTags($(this).attr('id'));
274
		// 	}
275
		//
276
		//
277
		// 	var url = '/apps/' + div.attr('data-provider');
278
		// 	var route = JSON.parse(div.attr('data-route'));
279
		//
280
		// 	route.url = url + route.url;
281
		// 	self.quickSearch(route, div.val(), function (res) {
282
		// 		self.resultTagsSearch(div, res);
283
		// 	});
284
		// });
285
286
		ul.append($('<li>').append(subAInput).append(subADataList));
287
	},
288
289
	displayPanelSearch: function (appId, ul, sub) {
290
		var self = this;
291
292
		if (sub.type !== 'search') {
293
			return;
294
		}
295
296
		var subAInput = $('<input>', {
297
			id: sub.name,
298
			class: 'search_tags_sub',
299
			type: 'text',
300
			placeholder: sub.title,
301
			list: sub.name + '_datalist',
302
			'data-option': sub.name,
303
			'data-provider': appId,
304
			'data-route': JSON.stringify(sub.route)
305
		});
306
307
		var subADataList = $('<datalist>', {
308
			id: sub.name + '_datalist'
309
		});
310
311
312
		subAInput.on('keypress', function (e) {
313
			var div = $(this);
314
			if (e.which === 13 && div.val() !== '') {
315
				self.selectPanelTags($(this).attr('id'));
316
			}
317
318
319
			var url = '/apps/' + div.attr('data-provider');
320
			var route = JSON.parse(div.attr('data-route'));
321
322
			route.url = url + route.url;
323
			self.quickSearch(route, div.val(), function (res) {
324
				self.resultTagsSearch(div, res);
325
			});
326
		});
327
328
		ul.append($('<li>').append(subAInput).append(subADataList));
329
	},
330
331
332
	// selectPanelTags: function (panelId) {
333
	// 	if (this.currentTagsResult === undefined) {
334
	// 		return;
335
	// 	}
336
	//
337
	// 	var tags = this.currentTagsResult[panelId];
338
	// 	if (tags.length === 0) {
339
	// 		return;
340
	// 	}
341
	//
342
	// 	if (this.selectedTags[panelId] === undefined)
343
	// 		this.selectedTags[panelId] = [];
344
	// 	this.selectedTags[panelId].push(tags[0]);
345
	//
346
	// 	console.log('etntree' + JSON.stringify(this.selectedTags[panelId]));
347
	// },
348
	//
349
	//
350
	// resultTagsSearch: function (div, res) {
351
	// 	this.currentTagsResult[div.attr('id')] = res;
352
	// 	var datalistId = div.attr('data-option') + '_datalist';
353
	// 	var datalist = $('#' + datalistId);
354
	//
355
	// 	datalist.empty();
356
	// 	res.forEach(function (item) {
357
	// 		datalist.append($('<option>', {value: item}));
358
	// 	});
359
	// },
360
361
362
	getProviders: function () {
363
		var providers = [];
364
		elements.search_panels.find('input').each(function () {
365
			if ($(this).hasClass('search_checkbox') && $(this).is(":checked")) {
366
				providers.push($(this).attr('data-provider-id'));
367
			}
368
		});
369
370
		if (providers.length === 0) {
371
			return 'all';
372
		}
373
374
		return providers;
375
	},
376
377
378
	getOptions: function () {
379
		var options = {};
380
		elements.search_panels.find('input').each(function () {
381
			if ($(this).hasClass('search_checkbox_sub')) {
382
				options[$(this).attr('data-option')] = (($(this).is(':checked')) ? '1' : '0');
383
			}
384
385
			if ($(this).hasClass('search_input_sub')) {
386
				options[$(this).attr('data-option')] = $(this).val();
387
			}
388
		});
389
390
		return options;
391
	},
392
393
394
	initSearch: function () {
395
		var search = elements.search_input.val();
396
397
		if (search.length < 1) {
398
			return false;
399
		}
400
401
		var providers = this.getProviders();
402
		var options = this.getOptions();
403
404
		this.displayProviderResults(providers);
405
406
		var request = {
407
			providers: providers,
408
			options: options,
409
			search: search,
410
			page: curr.page
0 ignored issues
show
Bug introduced by
The variable curr seems to be never declared. If this is a global, consider adding a /** global: curr */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
411
		};
412
413
		fullTextSearch.search(request, this.searchResult);
414
		return true;
415
	},
416
417
418
	quickSearch: function (route, search, callback) {
419
		$.ajax({
420
			method: route.verb,
421
			url: OC.generateUrl(route.url),
0 ignored issues
show
Bug introduced by
The variable OC seems to be never declared. If this is a global, consider adding a /** global: OC */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
422
			data: {
423
				search: search
424
			}
425
		}).done(function (res) {
426
			if (_.has(res, 'error')) {
427
				return;
428
			}
429
430
			callback(res);
431
		});
432
	},
433
434
435
	displayProviderResults: function (providers) {
436
		elements.search_result.children('DIV.provider_header').each(function () {
437
			if (providers === 'all' || providers.indexOf($(this).attr('data-id')) > -1) {
438
				$(this).stop().slideDown(100).fadeTo(settings.delay_provider, 1);
0 ignored issues
show
Bug introduced by
The variable settings seems to be never declared. If this is a global, consider adding a /** global: settings */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
439
			} else if ($(this).css('display') !== 'none') {
440
				$(this).stop().fadeTo(settings.delay_provider, 0).slideUp(100);
441
			}
442
		});
443
	},
444
445
446
	resetSearch: function () {
447
		// if (elements.search_input.val() !== '') {
448
		// 	return;
449
		// }
450
	},
451
452
453
	searchResult: function (result) {
454
455
		if (elements.search_json !== null) {
456
			elements.search_json.text(JSON.stringify(result));
457
		}
458
459
		// console.log(JSON.stringify(result));
460
//			OCA.notification.onFail('Search returned no result');
461
//		OCA.notification.onSuccess('Search returned ' + res.meta.size + ' result(s)');
462
463
	},
464
465
466
	onError: function (message) {
467
		console.log('error while searching: ' + message);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
468
	},
469
470
471
	// onEntryGenerated: function (entry) {
472
	// 	this.deleteEmptyDiv(entry, '#line1');
473
	// 	this.deleteEmptyDiv(entry, '#line2');
474
	// },
475
476
477
	deleteEmptyDiv: function (entry, divId) {
478
		var div = entry.find(divId);
479
		if (div.text() === '') {
480
			div.remove();
481
		}
482
	}
483
484
485
};
486
487
OCA.FullTextSearch.Example = Navigate;
488
489
490
$(document).ready(function () {
491
	OCA.FullTextSearch.example = new Navigate();
492
});
493
494
495
496